﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Golos.Polls.PollCache
{
    public partial class Cache
    {
        public void CreatePoll(PollInfo pollInfo)
        {
            if(!SaveNewPollInDb(pollInfo))
                throw new Exception("Can't create new poll");
            lock (lockcache)
            {
                questionPolls.Add(pollInfo.Id, pollInfo);
                if (!userOwnerQuestions.ContainsKey(pollInfo.OwnerUserId))
                    userOwnerQuestions.Add(pollInfo.OwnerUserId, new List<Guid>());
                userOwnerQuestions[pollInfo.OwnerUserId].Add(pollInfo.Id);
                questionUserAnswers.Add(pollInfo.Id, new Dictionary<Guid, UserAnswerInfo>());
                voicesCountCache.Add(pollInfo.Id, new Dictionary<Guid, int>());
            }
        }

        public void Vote(Guid questionId, Guid answerId, Guid userId, AnswerProperties answerProperties)
        {
            if (CheckUserAnswer(questionId, userId) != null)
                return;
            UserAnswerInfo userAnswerInfo = new UserAnswerInfo(userId, questionId, answerId, DateTime.UtcNow);
            if (!SaveUserVoteInDb(userAnswerInfo, answerProperties))
                throw new Exception("Can't save user vote");
            lock (lockcache)
            {
                if (!answerPropertiesCache.ContainsKey(answerId))
                    answerPropertiesCache.Add(answerId, new List<AnswerProperties>());
                answerPropertiesCache[answerId].Add(answerProperties);
                if (!voicesCountCache.ContainsKey(questionId))
                    voicesCountCache.Add(questionId, new Dictionary<Guid, int>());
                if (!voicesCountCache[questionId].ContainsKey(answerId))
                    voicesCountCache[questionId].Add(answerId, 0);
                voicesCountCache[questionId][answerId]++;
                if (!questionUserAnswers.ContainsKey(questionId))
                    questionUserAnswers.Add(questionId, new Dictionary<Guid, UserAnswerInfo>());
                if (!questionUserAnswers[questionId].ContainsKey(userId))
                    questionUserAnswers[questionId].Add(userId, userAnswerInfo);
                else
                    questionUserAnswers[questionId][userId] = userAnswerInfo;
                if (!userVotedQuestions.ContainsKey(userId))
                    userVotedQuestions.Add(userId, new List<Guid>());
                userVotedQuestions[userId].Add(questionId);
            }
        }

        public void MergeUserPoll(Guid userId, List<Guid> mergedUserIds)
        {
            if(!MergeUserPollInDb(userId, mergedUserIds))
                throw new Exception("Can't merge user poll in db");
            lock (lockcache)
            {
                //TODO Merge in memory

                foreach (Guid questionId in questionPolls.Keys)
                {
                    if (mergedUserIds.Contains(questionPolls[questionId].OwnerUserId))
                    {
                        questionPolls[questionId].SetOwner(userId);
                        if (!userOwnerQuestions.ContainsKey(userId))
                            userOwnerQuestions.Add(userId, new List<Guid>());
                        userOwnerQuestions[userId].Add(questionId);
                    }
                    foreach (Guid mergedUserId in mergedUserIds)
                    {
                        if(questionUserAnswers.ContainsKey(questionId))
                            if(questionUserAnswers[questionId].ContainsKey(mergedUserId))
                                if(questionUserAnswers[questionId].ContainsKey(userId))
                                {
                                    voicesCountCache[questionId][questionUserAnswers[questionId][mergedUserId].AnswerId]--;
                                    questionUserAnswers[questionId].Remove(mergedUserId);
                                    
                                }
                                else
                                {
                                    questionUserAnswers[questionId].Add(userId, questionUserAnswers[questionId][mergedUserId]);
                                    questionUserAnswers[questionId].Remove(mergedUserId);
                                }
                        if(userVotedQuestions.ContainsKey(mergedUserId))
                            if(userVotedQuestions[mergedUserId].Contains(questionId))
                                if(userVotedQuestions.ContainsKey(userId) && userVotedQuestions[userId].Contains(questionId))
                                {
                                    userVotedQuestions[mergedUserId].Remove(questionId);
                                }
                                else if(userVotedQuestions.ContainsKey(userId) && !userVotedQuestions[userId].Contains(questionId))
                                {
                                    userVotedQuestions[userId].Add(questionId);
                                    userVotedQuestions[mergedUserId].Remove(questionId);
                                }
                                else
                                {
                                    userVotedQuestions.Add(userId, new List<Guid>() {questionId});
                                    userVotedQuestions[mergedUserId].Remove(questionId);
                                }

                    }
                }
            }
        }

        public void Delete(Guid questionId)
        {
            lock (lockcache)
            {
                if(!MarkQuestionAsDeletedInDb(questionId))
                    throw new Exception("Can't mark question as deleted in db");
                questionPolls[questionId].Delete();
            }
        }
    }
}
